# This Python file uses the following encoding: utf-8
import sys
from typing import ClassVar
# from PySide6 import Qt
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QPushButton, QStatusBar, QTextEdit)
from PySide6.QtGui import (QClipboard)
from PySide6.QtCore import (Qt, Signal, Slot, QFile, QIODeviceBase, QThread, QObject, QTimer)

# Important:
# You need to run the following command to generate the ui_form.py file
#     pyside6-uic form.ui -o ui_form.py, or
#     pyside2-uic form.ui -o ui_form.py
from ui_mainwindow import Ui_MainWindow

try:
    # vscode
    import docs.docs_rc 
except:
    # qtcreator
    import docs.rc_docs 

from bs4 import BeautifulSoup
import requests
import json

# class RequestWorker(QThread): # 废弃 - 不如使用 RequestManager
#     requested = Signal(str, bool)
    
#     def __init__(self, url):
#         super(RequestWorker, self).__init__()
#         self.url = url
        
#     def run(self):
#         if len(self.url) == 0:
#             self.requested.emit('url 地址为空', False)
#             return
#         if not self.url.startswith('http'):
#             self.requested.emit('url 应该以 http:// 开头', False)
#             return

#         head = requests.head(self.url)
#         if not head.ok:
#             self.requested.emit(f'请求失败，代码：{head.status_code}', False)
#             return
        
#         resp = requests.get(self.url, headers={
#             'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'
#         })
        
#         if ct := resp.headers.get('Content-Type'):
#             if 'text' in ct:
#                 self.requested.emit(resp.content.decode(errors='ignore'), True)
#         else:
#             self.requested.emit(f'返回内容类型不正确: {ct}', False)

class RequestManager(QObject):
    request = Signal(str)
    requested = Signal(str, bool)
    
    requesting = Signal(str)
    
    def __init__(self, parent: QObject | None = ...) -> None:
        super().__init__(parent)
        
        self.m_thread = QThread()
        
    def stop(self):
        if self.m_thread.isRunning():
            self.m_thread.quit()
    
    def start(self):
        self.stop()

        self.worker = RequestWorker(self)
        self.request.connect(self.worker.request)
        self.m_thread.destroyed.connect(self.worker.deleteLater)
        self.worker.moveToThread(self.m_thread)
        self.m_thread.start()

class RequestWorker(QObject):
    
    def __init__(self, manager: RequestManager):
        super(RequestWorker, self).__init__()
        
        self.manager = manager
        
    @Slot()
    def request(self, url):
        request_log = f'准备请求: {url}'
        print(request_log)
        self.manager.requesting.emit(request_log)
        
        if len(url) == 0:
            self.manager.requested.emit('url 地址为空', False)
            return
        if not url.startswith('http'):
            self.manager.requested.emit('url 应该以 http:// 开头', False)
            return

        try:
            head = requests.head(url, timeout=(3.0,5.0))
        # except requests.exceptions.MissingSchema as e:
        #     self.manager.requested.emit(f'URL错误: \n{str(e)}', False)
        #     return
        # except requests.exceptions.InvalidURL as e:
        #     self.manager.requested.emit(f'URL错误: \n{str(e)}', False)
        #     return
        # except requests.exceptions.ConnectionError as e:
        except requests.exceptions.RequestException as e:
            self.manager.requested.emit(f'链接错误: \n{str(e)}', False)
            return
        
        if not head.ok:
            self.manager.requested.emit(f'请求失败，代码：{head.status_code}', False)
            return
        
        resp = requests.get(url, headers={
            'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'
        })
        
        if ct := resp.headers.get('Content-Type'):
            if 'text' in ct:
                self.manager.requested.emit(resp.content.decode(errors='ignore'), True)
        else:
            self.manager.requested.emit(f'返回内容类型不正确: {ct}', False)

import bs4
class SoupManager(QObject):
    
    soup = Signal(str)
    souped = Signal(str, bool)
    
    soup_select = Signal(str, str)
    souped_select = Signal(list, bool)
    
    soup_find = Signal(str, str)
    souped_find = Signal(bs4.element.Tag, bool)
    
    soup_findall = Signal(str, str)
    souped_findall = Signal(list, bool)
    
    def __init__(self, parent: QObject | None = ...) -> None:
        super().__init__(parent)
        
        self.m_thread = QThread()
        
    def stop(self):
        if self.m_thread.isRunning():
            self.m_thread.quit()
    
    def start(self):
        self.stop()

        self.worker = SoupWorker(self)
        self.soup.connect(self.worker.soup)
        self.soup_select.connect(self.worker.soup_select)
        self.soup_find.connect(self.worker.soup_find)
        self.soup_findall.connect(self.worker.soup_findall)
        self.m_thread.destroyed.connect(self.worker.deleteLater)
        self.worker.moveToThread(self.m_thread)
        self.m_thread.start()

class SoupWorker(QObject):
    
    def __init__(self, manager: SoupManager) -> None:
        super().__init__()
        
        self.manager = manager
      
    @Slot()  
    def soup(self, text):
        soup = BeautifulSoup(text, 'html.parser')
        if len(soup.contents) > 0:
            self.manager.souped.emit('soup: 正确的内容.', True)
        else:
            self.manager.souped.emit('soup: 不是正确的内容.', False)
            
    @Slot()  
    def soup_select(self, text, select_text):
        try:
            soup = BeautifulSoup(text, 'html.parser')
            datas = soup.select(select_text)
            self.manager.souped_select.emit(datas, True)
        except:
            datas = []
            self.manager.souped_select.emit(datas, False)
            
    @Slot()  
    def soup_find(self, text, find_text):
        try:
            soup = BeautifulSoup(text, 'html.parser')
            data = soup.find(find_text)
            self.manager.souped_find.emit(data, False)
        except:
            data = None
            self.manager.souped_find.emit(data, False)
            
    @Slot()
    def soup_findall(self, text, findall_text):
        try:
            soup = BeautifulSoup(text, 'html.parser')
            datas = soup.find_all(findall_text)
            self.manager.souped_findall.emit(datas, False)
        except:
            datas = []
            self.manager.souped_findall.emit(datas, False)

class SoupThread(QThread): # 废弃 - 不如使用 SoupManager
    done = Signal(str)
    
    def __init__(self):
        super(SoupThread, self).__init__()
        self.exiting = False
        
    def run(self):
        # while not self.exiting:
        soup = BeautifulSoup(self.ui.input.toPlainText(), 'html.parser')
        
    def stop(self):
        self.exiting = True

class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # 编辑 soup 时，进行延时响应
        self.soup_countdown = 3
        self.soup_timer = QTimer()
        self.soup_timer.setInterval(1000)
        self.soup_timer.timeout.connect(self.on_soup_timer_timeout)
        
        # 准备状态
        self.ready = False
        self.ready_copy = False
        # self.request_thread = None
        self.request_manager = RequestManager(self)
        self.request_manager.requested.connect(self.slot_requested_message)
        self.request_manager.requesting.connect(self.slot_requesting_message)
        self.request_manager.start()
        
        self.soup_manager = SoupManager(self)
        self.soup_manager.souped.connect(self.slot_souped_message)
        self.soup_manager.souped_select.connect(self.slot_souped_select_message)
        self.soup_manager.souped_find.connect(self.slot_souped_find_message)
        self.soup_manager.souped_findall.connect(self.slot_souped_findall_message)
        self.soup_manager.start()
        
        # --- 顶部控件事件连接器
        self.ui.r_url.clicked.connect(self.checkUrl)
        self.ui.url.textChanged.connect(lambda x: self.checkUrl())
        self.ui.r_xml.clicked.connect(self.on_input_textChanged)
        
        # --- 菜单控件事件连接器
        self.ui.action_about.triggered.connect(self.about)
        self.ui.action_about_qt.triggered.connect(QApplication.aboutQt)

        # --- 底部按钮事件连接器
        self.ui.b_copy_soup.clicked.connect(self.copyBeautifulSoup)
        self.ui.b_copy_json.clicked.connect(self.copyJson)

    @Slot()
    def about(self):
        # - 读取内置手册
        manual = QFile('://manual.md')
        manual.open(QIODeviceBase.OpenModeFlag.ReadOnly)
        content = manual.readAll().toStdString()
        manual.close()

        # - 设置内容
        self.textedit = QTextEdit()
        self.textedit.setWindowTitle('帮助')
        self.textedit.setReadOnly(True)
        self.textedit.setMarkdown(content)

        # - 计算位置与对话框大小信息
        rect = self.geometry()
        rect.setWidth(700)
        rect.setHeight(500)
        rect.moveCenter(self.geometry().center())
        self.textedit.setGeometry(rect)

        # - 显示
        self.textedit.show()

    @Slot()
    def copyBeautifulSoup(self):
        clipboard = QApplication.clipboard()
        clip_text = ''
        
        if self.ui.r_select.isChecked():
            if self.ui.r_show_all.isChecked():
                clip_text = "soup.select('''{}''')".format(self.ui.soup.text())
            
            if self.ui.r_show_one.isChecked():
                clip_text = "soup.select('''{}''')[0]".format(self.ui.soup.text())

            if self.ui.r_show_attrs.isChecked():
                clip_text = "soup.select('''{}''')[0].attrs".format(self.ui.soup.text())

            if self.ui.r_show_text.isChecked():
                clip_text = "soup.select('''{}''')[0].text".format(self.ui.soup.text())

        if self.ui.r_find.isChecked():
            if self.ui.r_show_all.isChecked():
                clip_text = "soup.find('''{}''')".format(self.ui.soup.text())
            
            if self.ui.r_show_one.isChecked():
                clip_text = "soup.find('''{}''')".format(self.ui.soup.text())

            if self.ui.r_show_attrs.isChecked():
                clip_text = "soup.find('''{}''').attrs".format(self.ui.soup.text())

            if self.ui.r_show_text.isChecked():
                clip_text = "soup.find('''{}''').text".format(self.ui.soup.text())

        if self.ui.r_findall.isChecked():
            if self.ui.r_show_all.isChecked():
                clip_text = "soup.find_all('''{}''')".format(self.ui.soup.text())
            
            if self.ui.r_show_one.isChecked():
                clip_text = "soup.find_all('''{}''')[0]".format(self.ui.soup.text())

            if self.ui.r_show_attrs.isChecked():
                clip_text = "soup.find_all('''{}''')[0].attrs".format(self.ui.soup.text())

            if self.ui.r_show_text.isChecked():
                clip_text = "soup.find_all('''{}''')[0].text".format(self.ui.soup.text())

        clipboard.setText(clip_text)
        self.message(f'已拷贝 soup 内容到剪贴板. - {clip_text}')
    
    def maybe_copy_json_datas(self, datas):
        clipboard = QApplication.clipboard()
        clip_text = ''
        if self.ready_copy:
            
            container = []
            
            if self.ui.r_show_all_attrs.isChecked():
                attr = self.ui.e_attr.text()
                for data in datas:
                    if attr != "":
                        if len(attr.split(',')) > 1:
                            obj = {}
                            for attritem in [i.strip() for i in attr.split(',')]:
                                obj[attritem] = str(data.attrs[attritem]).strip()
                            container.append(obj)
                            continue
                        container.append(str(data.attrs[attr]).strip())
                        continue
                    else:
                        container.append(str(data.attrs).strip())
            if self.ui.r_show_all_text.isChecked():
                for data in datas:
                    container.append(str(data.text).strip())
            
            clip_text = json.dumps(container)
            clipboard.setText(clip_text)
            
            self.ready_copy = False
            self.message(f'已拷贝 json 内容到剪贴板.')
            
    
    @Slot()
    def copyJson(self):
        self.ready_copy = True
        text = self.ui.soup.text()
        self.on_soup_textChanged(text)

    
    @Slot()
    def slot_requested_message(self, str, success):
        if success:
            self.ready = True
            self.ui.input.setPlainText(str)
            
        else:
            self.ready = False
            self.ui.input.setPlainText(str)
            
    @Slot()
    def slot_requesting_message(self, str):
        self.message(str)
    
    @Slot()
    def checkUrl(self):
        self.ready = False

        url = self.ui.url.text().strip()
        self.message("请求中...")
        self.request_manager.request.emit(url)
        
        # 以下逻辑转到 RequestWorker 完成
        # if len(url) == 0:
        #     self.ui.input.setPlainText('url 地址为空')
        #     return
        # if not url.startswith('http'):
        #     self.ui.input.setPlainText('url 应该以 http:// 开头')
        #     return

        # head = requests.head(url)
        # if not head.ok:
        #     self.ui.input.setPlainText(f'请求失败，代码：{head.status_code}')
        #     return
        
        # resp = requests.get(url, headers={
        #     'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'
        # })
        # if ct := resp.headers.get('Content-Type'):
        #     if 'text' in ct:
        #         self.ready = True
        #         self.ui.input.setPlainText(resp.content.decode(errors='ignore'))
        # else:
        #     self.ui.input.setPlainText(f'返回内容类型不正确: {ct}')

    def slot_souped_message(self, str, success):
        if success:
            self.ready = True
            self.ui.soup.setEnabled(True)
            self.ui.output.setPlainText(str)

    @Slot()
    def on_input_textChanged(self):
        if self.ready != True and self.ui.r_url.isChecked():
            self.ui.output.setPlainText('内容: 还没有准备好.')
            return

        self.ready = False  
        text = self.ui.input.toPlainText()
        self.soup_manager.soup.emit(text)
        
        # 以下逻辑转到 SoupWorker 完成
        # soup = BeautifulSoup(text, 'html.parser')
        # if len(soup.contents) > 0:
        #     self.ready = True
        #     self.ui.soup.setEnabled(True)
        #     self.message("正确的内容")
        #     self.ui.output.setPlainText('正确的内容.')
        # else:
        #     self.ui.soup.setEnabled(False)
        #     self.message("不是正确的内容")
        #     self.ui.output.setPlainText('不是正确的内容.')
            

        # if soup.is_xml:
        #     self.ui.output.setPlainText('正确的 xml 内容.')
        #     self.ready = True
        #     self.ui.soup.setEnabled(True)
        # else:
        #     self.message("不是正确的 xml 内容")
        #     self.ui.output.setPlainText('不是正确的 xml 内容.')
        #     self.ui.soup.setEnabled(False)
    
    def get_text_return(self):
        text = ''
        for i in range(0, self.ui.s_return.value()):
            text += '\n'
        if text == '\n':
            text = ' '
        return text
    
    @Slot()
    def slot_souped_select_message(self, datas: bs4.element.ResultSet[bs4.element.Tag], success):
        if not success:
            self.message('内部发生错误，已恢复')
            
        text_return = self.get_text_return()
                    
        if len(datas) == 0:
            self.ui.output.setPlainText('没有任何内容.')
            self.ui.b_topology.setEnabled(False)
            return
        else:
            self.message(f'已捕获到 {len(datas)} 条数据.')

            # 右侧 all(attrs、text)、one(attrs、text)
            if self.ui.r_show_all.isChecked():
                for data in datas:
                    self.ui.output.appendPlainText(str(data).strip())
                    if text_return != '':
                        self.ui.output.appendPlainText(text_return)

            if self.ui.r_show_all_attrs.isChecked():
                attr = self.ui.e_attr.text()
                for data in datas:
                    if attr != "":
                        if len(attr.split(',')) > 1:
                            obj = {}
                            for attritem in [i.strip() for i in attr.split(',')]:
                                obj[attritem] = str(data.attrs[attritem]).strip()
                            self.ui.output.appendPlainText(json.dumps(obj))
                        else:
                            try:
                                self.ui.output.appendPlainText(str(data.attrs[attr]).strip())
                            except:
                                self.message("发生异常")
                    else:
                        self.ui.output.appendPlainText(str(data.attrs).strip())

                    if text_return != '':
                        self.ui.output.appendPlainText(text_return)
                self.maybe_copy_json_datas(datas)
                    
            if self.ui.r_show_all_text.isChecked():
                for data in datas:
                    self.ui.output.appendPlainText(str(data.text).strip())
                    if text_return != '':
                        self.ui.output.appendPlainText(text_return)
                self.maybe_copy_json_datas(datas)
            
            if self.ui.r_show_one.isChecked():
                one_str = str(datas[0])
                if self.ui.c_format.isChecked():
                    one_str = str(datas[0].prettify())
                self.ui.output.appendPlainText(one_str)
                self.ui.b_topology.setEnabled(True)

            if self.ui.r_show_attrs.isChecked():
                attr = self.ui.e_attr.text()
                if attr != "":
                    if len(attr.split(',')) > 1:
                        obj = {}
                        for attritem in [i.strip() for i in attr.split(',')]:
                            obj[attritem] = str(datas[0].attrs[attritem]).strip()
                        self.ui.output.appendPlainText(json.dumps(obj))
                    else:
                        try:
                            self.ui.output.appendPlainText(str(datas[0].attrs[attr]).strip())
                        except:
                            self.message("发生异常")
                else:
                    self.ui.output.appendPlainText(str(datas[0].attrs).strip())

            if self.ui.r_show_text.isChecked():
                self.ui.output.appendPlainText(str(datas[0].text).strip())
                
    @Slot()
    def slot_souped_find_message(self, data, success):
        if success:
            self.message('内部发生错误，已恢复')
        
        if data == None:
            self.ui.output.setPlainText('没有任何内容.')
            return
        else:
            self.message(f'已捕获到 1 条数据.')

            # 右侧 all、one、attrs、text
            if self.ui.r_show_all.isChecked():
                self.ui.output.appendPlainText('不支持 all 显示')
                # self.ui.output.appendPlainText(datas)
            
            if self.ui.r_show_one.isChecked():
                one_str = str(data)
                if self.ui.c_format.isChecked():
                    one_str = str(data.prettify())
                self.ui.output.appendPlainText(one_str)
                self.ui.b_topology.setEnabled(True)

            if self.ui.r_show_attrs.isChecked():
                self.ui.output.appendPlainText(str(data.attrs))

            if self.ui.r_show_text.isChecked():
                self.ui.output.appendPlainText(str(data.text))
                
    @Slot()
    def slot_souped_findall_message(self, datas, success):
        if success:
            self.message('内部发生错误，已恢复')
            
        text_return = self.get_text_return()
        
        if len(datas) == 0:
            self.ui.output.setPlainText('没有任何内容.')
            return
        else:
            self.message(f'已捕获到 {len(datas)} 条数据.')
            
            # 右侧 all、one、attrs、text
            if self.ui.r_show_all.isChecked():
                for data in datas:
                    self.ui.output.appendPlainText(str(data))
                    self.ui.output.appendPlainText(text_return)

            if self.ui.r_show_one.isChecked():
                one_str = str(datas[0])
                if self.ui.c_format.isChecked():
                    one_str = str(datas[0].prettify())
                self.ui.output.appendPlainText(one_str)
                self.ui.b_topology.setEnabled(True)

            if self.ui.r_show_attrs.isChecked():
                self.ui.output.appendPlainText(str(datas[0].attrs))

            if self.ui.r_show_text.isChecked():
                self.ui.output.appendPlainText(str(datas[0].text))
        
    
    # ------ 中间输入控件事件
    @Slot(str)
    def on_soup_textChanged(self, text:str):
        self.soup_timer.stop()
        self.soup_countdown = 3
        self.on_soup_timer_timeout()
        self.soup_timer.start()

    @Slot()
    def on_soup_timer_timeout(self):
        
        if self.soup_countdown > 0:
            self.message(f'soup: 即将开始({self.soup_countdown})')
            self.soup_countdown = self.soup_countdown - 1
            return
        self.soup_timer.stop()

        text = self.ui.soup.text()

        # self.ui.soup.textChanged
        if self.ready != True:
            self.message('soup: 还没有准备好.')
            return

        if len(text) == 0:
            self.message('soup: 输入内容为空.')
            return
        
        # soup = BeautifulSoup(self.ui.input.toPlainText(), 'html.parser')
        
        # if not soup.is_xml:
        #     self.message('非 xml 内容.')
        #     self.ui.output.setPlainText('非 xml 内容.')
        #     return

        # -- 左侧 select 
        if self.ui.r_select.isChecked():
            self.ui.output.clear()
            
            self.message("Soup: 正在执行 select ...")
            self.soup_manager.soup_select.emit(self.ui.input.toPlainText(), text)
            
            # 以下逻辑转到 SoupWorker 处理
            # try:
            #     datas = soup.select(text)
            # except:
            #     datas = []
            #     self.manager.souped_select.emit(datas, False)
            
            # if len(datas) == 0:
            #     self.ui.output.setPlainText('没有任何内容.')
            #     self.ui.b_topology.setEnabled(False)
            #     return
            # else:
            #     self.message(f'已捕获到 {len(datas)} 条数据.')

            #     # 右侧 all(attrs、text)、one(attrs、text)
            #     if self.ui.r_show_all.isChecked():
            #         for data in datas:
            #             self.ui.output.appendPlainText(str(data).strip())
            #             if text_return != '':
            #                 self.ui.output.appendPlainText(text_return)
                        
            #     if self.ui.r_show_all_attrs.isChecked():
            #         for data in datas:
            #             self.ui.output.appendPlainText(str(data.attrs).strip())
            #             if text_return != '':
            #                 self.ui.output.appendPlainText(text_return)
                        
            #     if self.ui.r_show_all_text.isChecked():
            #         for data in datas:
            #             self.ui.output.appendPlainText(str(data.text).strip())
            #             if text_return != '':
            #                 self.ui.output.appendPlainText(text_return)
                
            #     if self.ui.r_show_one.isChecked():
            #         one_str = str(datas[0])
            #         if self.ui.c_format.isChecked():
            #             one_str = str(datas[0].prettify())
            #         self.ui.output.appendPlainText(one_str)
            #         self.ui.b_topology.setEnabled(True)

            #     if self.ui.r_show_attrs.isChecked():
            #         self.ui.output.appendPlainText(str(datas[0].attrs).strip())

            #     if self.ui.r_show_text.isChecked():
            #         self.ui.output.appendPlainText(str(datas[0].text).strip())

            
        # -- 左侧 find
        if self.ui.r_find.isChecked():
            self.ui.output.clear()
            
            self.message("Soup: 正在执行 find ...")
            self.soup_manager.soup_find.emit(self.ui.input.toPlainText(), text)
            
            
            # 以下逻辑转到 SoupWorker 处理
            # try:
            #     data = soup.find(text)
            # except:
            #     self.message('内部发生错误，已恢复')
            #     data = None
            
            # if data == None:
            #     self.ui.output.setPlainText('没有任何内容.')
            #     return
            # else:
            #     self.message(f'已捕获到 1 条数据.')

            #     # 右侧 all、one、attrs、text
            #     if self.ui.r_show_all.isChecked():
            #         self.ui.output.appendPlainText('不支持 all 显示')
            #         # self.ui.output.appendPlainText(datas)
                
            #     if self.ui.r_show_one.isChecked():
            #         one_str = str(data)
            #         if self.ui.c_format.isChecked():
            #             one_str = str(data.prettify())
            #         self.ui.output.appendPlainText(one_str)
            #         self.ui.b_topology.setEnabled(True)

            #     if self.ui.r_show_attrs.isChecked():
            #         self.ui.output.appendPlainText(str(data.attrs))

            #     if self.ui.r_show_text.isChecked():
            #         self.ui.output.appendPlainText(str(data.text))

        # -- 左侧 findall 
        if self.ui.r_findall.isChecked():
            self.ui.output.clear()
            
            self.message("Soup: 正在执行 find_all ...")            
            self.soup_manager.soup_findall.emit(self.ui.input.toPlainText(), text)
            
            # try:
            #     datas = soup.find_all(text)
            # except:
            #     self.message('内部发生错误，已恢复')
            #     datas = []

            # if len(datas) == 0:
            #     self.ui.output.setPlainText('没有任何内容.')
            #     return
            # else:
            #     self.message(f'已捕获到 {len(datas)} 条数据.')
                
            #     # 右侧 all、one、attrs、text
            #     if self.ui.r_show_all.isChecked():
            #         for data in datas:
            #             self.ui.output.appendPlainText(str(data))
            #             self.ui.output.appendPlainText("\n\n")

            #     if self.ui.r_show_one.isChecked():
            #         one_str = str(datas[0])
            #         if self.ui.c_format.isChecked():
            #             one_str = str(datas[0].prettify())
            #         self.ui.output.appendPlainText(one_str)
            #         self.ui.b_topology.setEnabled(True)

            #     if self.ui.r_show_attrs.isChecked():
            #         self.ui.output.appendPlainText(str(datas[0].attrs))

            #     if self.ui.r_show_text.isChecked():
            #         self.ui.output.appendPlainText(str(datas[0].text))
    
    # ------- 中间左、右控件事件
    @Slot()
    def on_c_format_clicked(self):
        self.ui.b_topology.setEnabled(False)
        self.on_soup_textChanged(self.ui.soup.text())

    @Slot()
    def on_b_topology_clicked(self):
        text = self.ui.output.toPlainText()
        self.ui.input.setPlainText(text)
        self.message('拓扑开始.')

    # ------- 下方左侧控件事件
    @Slot()
    def on_r_select_clicked(self):
        self.ui.b_topology.setEnabled(False)
        self.on_soup_textChanged(self.ui.soup.text())

    @Slot()
    def on_r_find_clicked(self):
        self.ui.b_topology.setEnabled(False)
        self.on_soup_textChanged(self.ui.soup.text())

    @Slot()
    def on_r_findall_clicked(self):
        self.ui.b_topology.setEnabled(False)
        self.on_soup_textChanged(self.ui.soup.text())
    
    @Slot()
    def on_s_return_valueChanged(self):
        text = self.ui.soup.text()
        self.on_soup_textChanged(text)
            
    @Slot()
    def on_e_attr_returnPressed(self):
        if self.ui.r_show_all_attrs.isChecked() or self.ui.r_show_attrs.isChecked():
            text = self.ui.soup.text()
            self.on_soup_textChanged(text)

    # ------- 下方右侧控件事件
    @Slot()
    def on_r_show_all_clicked(self):
        self.ui.b_topology.setEnabled(False)
        self.on_soup_textChanged(self.ui.soup.text())

    @Slot()
    def on_r_show_all_attrs_clicked(self):
        self.ui.b_topology.setEnabled(False)
        self.on_soup_textChanged(self.ui.soup.text())
        
    @Slot()
    def on_r_show_all_text_clicked(self):
        self.ui.b_topology.setEnabled(False)
        self.on_soup_textChanged(self.ui.soup.text())
    
    # - one
    @Slot()
    def on_r_show_one_clicked(self):
        self.on_soup_textChanged(self.ui.soup.text())

    @Slot()
    def on_r_show_attrs_clicked(self):
        self.ui.b_topology.setEnabled(False)
        self.on_soup_textChanged(self.ui.soup.text())

    @Slot()
    def on_r_show_text_clicked(self):
        self.ui.b_topology.setEnabled(False)
        self.on_soup_textChanged(self.ui.soup.text())
    # -------
        
    def message(self, txt):
        self.ui.statusbar.showMessage(txt)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    widget = MainWindow()
    widget.show()
    sys.exit(app.exec())
